package cc.rengu.igas.share.core.service.channel.alipay;

import cc.rengu.igas.channel.alipay.facade.base.Header;
import cc.rengu.igas.channel.alipay.facade.bean.ExtraParam;
import cc.rengu.igas.channel.alipay.facade.request.AliFundFreezeRequest;
import cc.rengu.igas.channel.alipay.facade.response.AliFundFreezeResponse;
import cc.rengu.igas.channel.alipay.facade.result.Result;
import cc.rengu.igas.share.common.constant.ShareParamConstant;
import cc.rengu.igas.share.common.constant.ShareServiceConstant;
import cc.rengu.igas.share.core.model.MchntInfo;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.oltp.service.base.ChannelBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.DstChannelCfgMapper;
import cc.rengu.oltp.service.common.dao.impl.DstChannelCfgMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.model.TxnInfo;
import cc.rengu.oltp.service.realize.DubboService;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 资金冻结服务
 * Created by wangcheng on 2022/2/15 14:48
 */
public class AliFundFreezeService extends ChannelBaseService {
    @Override
    public Object callPreProc(TxnInfo txnInfo, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        Header aliHeader = new Header();
        aliHeader.setInstId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID));
        aliHeader.setChanlId(channelCallCfg.getMsgSrcId());
        aliHeader.setSrcSysId(AppParamConstant.SYS_ID);
        aliHeader.setBizType(AppParamConstant.DEFAULT_BIZ_TYPE);
        aliHeader.setVersion(ShareParamConstant.DUBBO_VSERSION);
        aliHeader.setTxnNum(channelCallCfg.getCallChannelTxn());
        aliHeader.setTraceNo(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM) + channelCallCfg.getCallIndex());
        aliHeader.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        aliHeader.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));

        MchntService mchntService = new MchntServiceImpl();
        MchntInfo mchntInfo = mchntService.getMchntInfo(aliHeader.getInstId(), xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.MCHNT_NO));
        AliFundFreezeRequest aliFundFreezeRequest = new AliFundFreezeRequest();
        aliFundFreezeRequest.setHeader(aliHeader);
        aliFundFreezeRequest.setChannelId(channelCallCfg.getCallChannelId());
        aliFundFreezeRequest.setChannelType(mchntInfo.getAlipayChannelType());
        aliFundFreezeRequest.setAppAuthToken(mchntInfo.getAlipayAppAuthToken());
        /*预授权码*/
        aliFundFreezeRequest.setPayCode(xmlTreeUtil.getXmlTreeStringValue("payQrCode"));
        /*授权码类型 */
        aliFundFreezeRequest.setPayType("bar_code");
        /*设置支付宝下单订单号*/
        aliFundFreezeRequest.setMchntOrderId(orderInfo.getMchntOrderInfoList().get(0).getMchntOrderId());
        /*商户本次资金操作的请求流水号*/
        aliFundFreezeRequest.setReqTraceNo(aliHeader.getTraceNo());
        /*业务订单描述*/
        aliFundFreezeRequest.setOrderDesc(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.ORDER_DESC));
        /*冻结金额*/
        aliFundFreezeRequest.setFreezeAmt(orderInfo.getUserOrderInfo().getRealPayAmt());
        /*允许最晚付款时间*/
        long payExpiryTime = Long.parseLong(orderInfo.getUserOrderInfo().getOrderExpiryTime()) - Long.parseLong(orderInfo.getUserOrderInfo().getOrderCreateTime());
        String payTimeOut = (payExpiryTime / 1000) / 60 + "m";
        aliFundFreezeRequest.setTimeoutExpr(payTimeOut);
        /*业务扩展参数*/
        ExtraParam extraParam = new ExtraParam();
        /*支付宝子商户号*/
        extraParam.setSecondaryMerchantId(mchntInfo.getAlipayMchntNo());
        /*当面付业务种类,由支付宝分配，酒店业务传"HOTEL"，若使用信用预授权，则该值必传*/
//        extraParam.setCategory("");
        /*信用服务Id,信用场景下必传，具体值需要联系芝麻客服*/
//        extraParam.setServiceId("");
        /*设置PID*/
        DstChannelCfgMapper dstChannelCfgMapper = new DstChannelCfgMapperImpl();
        DstChannelCfg dstChannelCfg = dstChannelCfgMapper.selectDstChannelCfgByPrimaryKey(channelCallCfg.getInstId(), channelCallCfg.getCallChannelId(), mchntInfo.getAlipayChannelType());
        extraParam.setRequestOrgId(dstChannelCfg.getProviderMchntNo());
        aliFundFreezeRequest.setExtendParam(extraParam);
        /*销售产品码*/
        aliFundFreezeRequest.setProductCode("PRE_AUTH");
        return aliFundFreezeRequest;
    }

    @Override
    public PayOrderInfo generatePayOrderInfo(ChannelCallCfg channelCallCfg, OrderInfo orderInfo, Object request) throws Exception {
        PayOrderInfo payOrderInfo = new PayOrderInfo();
        AliFundFreezeRequest aliFundFreezeRequest = (AliFundFreezeRequest) request;
        BeanUtil.beanCopy(orderInfo.getUserOrderInfo(), payOrderInfo);
        if (orderInfo.getMchntOrderInfoList().size() == 1) {
            payOrderInfo.setMchntNo(orderInfo.getMchntOrderInfoList().get(0).getMchntNo());
        } else {
            payOrderInfo.setMchntNo(orderInfo.getUserOrderInfo().getGroupMchntNo());
        }
        payOrderInfo.setTxnNum(channelCallCfg.getTxnNum());
        payOrderInfo.setBizType(channelCallCfg.getBizType());
        payOrderInfo.setSysSeqNum(orderInfo.getUserOrderInfo().getSysSeqNum());
        payOrderInfo.setOrderCcy(orderInfo.getUserOrderInfo().getOrderCcy());
        payOrderInfo.setMsgDstId(channelCallCfg.getCallChannelId());
        payOrderInfo.setDstCallIndex(channelCallCfg.getCallIndex());
        MchntService mchntService = new MchntServiceImpl();
        MchntInfo mchntInfo = mchntService.getMchntInfo(Objects.requireNonNull(aliFundFreezeRequest).getHeader().getInstId(), orderInfo.getMchntOrderInfoList().get(0).getMchntNo());
        payOrderInfo.setDstChannelType(mchntInfo.getAlipayChannelType());
        payOrderInfo.setChannelSeqNum(aliFundFreezeRequest.getHeader().getTraceNo());
        payOrderInfo.setChannelReconKey(orderInfo.getUserOrderInfo().getSysSeqNum());
        payOrderInfo.setDstTxnNum(channelCallCfg.getCallChannelTxn());
        payOrderInfo.setPayType(PayTypeEnum.ALIPAY.getPayType());
        payOrderInfo.setPayerAcctType(AcctTypeEnum.ALL.getAcctType());
        payOrderInfo.setPayerAcctInfo(aliFundFreezeRequest.getPayCode());
        payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
        payOrderInfo.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        payOrderInfo.setUserId(orderInfo.getUserOrderInfo().getUserId());
        return payOrderInfo;
    }

    @Override
    public Object callProc(ChannelCallCfg channelCallCfg, Object request) throws Exception {
        AliFundFreezeRequest aliFundFreezeRequest = (AliFundFreezeRequest) request;
        /* Step1：调用接口，获取结果 */
        Result<AliFundFreezeResponse> callResult;
        DubboService dubboService = new DubboServiceImpl();
        if (AppParamConstant.YES.equals(channelCallCfg.getSyncCallFlag())) {
            /* Step1.1：异步调用 */
            int iReturnCode;
            int callTimes = 0 == channelCallCfg.getSyncQueryRepeatNum() ? 1 : channelCallCfg.getSyncQueryRepeatNum();
            int gatTime = channelCallCfg.getSyncQueryRepeatTime();
            int gatType = StringUtil.isEmptyOrNull(channelCallCfg.getSyncQueryGapType()) ? 0 : Integer.parseInt(channelCallCfg.getSyncQueryGapType());
            if (ChannelCallModeEnum.LOCAL.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.1.1：异步应用内调用 */
                Class clasz = Class.forName(ShareServiceConstant.ALIPAY_PAY_SERVICE_INNER_PATH);
                iReturnCode = dubboService.asynCallDubboInnerMethod(clasz, ShareServiceConstant.ALI_FUND_FREEEZE_METHOD, aliFundFreezeRequest, channelCallCfg.getSyncResultServiceName(), callTimes, gatType, gatTime);
            } else if (ChannelCallModeEnum.REMOTE.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.1.2：异步远程调用 */
                iReturnCode = dubboService.asynCallDubboService(ShareServiceConstant.ALIPAY_PAY_SERVICE, ShareServiceConstant.ALI_FUND_FREEEZE_METHOD, aliFundFreezeRequest, channelCallCfg.getSyncResultServiceName(), callTimes, gatType, gatTime);
            } else {
                rglog.error("不支持的通道服务调用方式:{}，交易拒绝!", channelCallCfg.getChannelCallMode());
                throw new BizException(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR);
            }
            if (0 == iReturnCode) {
                return new BizResponse<>(OltpRpcdEnum.TRANS_SUCCESS.getRespCode(), OltpRpcdEnum.TRANS_SUCCESS.getRespDesc());
            } else {
                return new BizResponse<>(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(), OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
            }
        } else {
            /* Step1.2：同步调用 */
            if (ChannelCallModeEnum.LOCAL.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.2.1：同步应用内调用 */
                Class clasz = Class.forName(ShareServiceConstant.ALIPAY_PAY_SERVICE_INNER_PATH);
                callResult = (Result<AliFundFreezeResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.ALI_FUND_FREEEZE_METHOD, aliFundFreezeRequest);
            } else if (ChannelCallModeEnum.REMOTE.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.2.2：同步远程调用 */
                callResult = (Result<AliFundFreezeResponse>) dubboService.callDubboService(ShareServiceConstant.ALIPAY_PAY_SERVICE, ShareServiceConstant.ALI_FUND_FREEEZE_METHOD, aliFundFreezeRequest);
            } else {
                rglog.error("不支持的通道服务调用方式:{}，交易拒绝!", channelCallCfg.getChannelCallMode());
                throw new BizException(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR);
            }
        }
        return callResult;
    }

    @Override
    public Object querySyncCallResult(PayOrderInfo payOrderInfo, Object request) {
        return null;
    }

    @Override
    public OrderInfo callResultOrderProc(OrderInfo orderInfo, String payOrderIndex, TransStatusEnum transStatusEnum, Object response) throws Exception {
        OrderInfo updateOrderInfo = new OrderInfo();
        Result<AliFundFreezeResponse> callResult = (Result<AliFundFreezeResponse>) response;
        Optional<PayOrderInfo> payOrderInfoOpt = orderInfo.getPayOrderInfoList().stream().filter(item -> item.getDstCallIndex().equals(payOrderIndex)).findFirst();
        if (payOrderInfoOpt.isPresent() && null != callResult && null != callResult.getResult()) {
            AliFundFreezeResponse aliFundFreezeResponse = callResult.getResult();
            UserOrderInfo userOrderInfo = orderInfo.getUserOrderInfo();
            List<MchntOrderInfo> mchntOrderInfoList = orderInfo.getMchntOrderInfoList();
            PayOrderInfo payOrderInfo = payOrderInfoOpt.get();
            payOrderInfo.setTransStatus(transStatusEnum.getStatus());
            payOrderInfo.setRespCode(aliFundFreezeResponse.getRespCode());
            payOrderInfo.setRespDesc(aliFundFreezeResponse.getRespDesc());
            payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
            switch (transStatusEnum) {
                case TRANS_SUCC:
                    if ("SUCCESS".equals(aliFundFreezeResponse.getStatus())) {
                        /* 更新支付订单信息 */
                        userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
                        userOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                        userOrderInfo.setBizStatus(BizStatusEnum.AUTH_INCOMPLETE.getStatus());
                        userOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        /* 更新商户订单信息 */
                        for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
                            mchntOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                            mchntOrderInfo.setBizStatus(BizStatusEnum.AUTH_INCOMPLETE.getStatus());
                            mchntOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        }
                        updateOrderInfo.setUserOrderInfo(userOrderInfo);
                        updateOrderInfo.setMchntOrderInfoList(mchntOrderInfoList);
                        /* 更新支付订单信息 */
                        payOrderInfo.setPayerAcctType(AcctTypeEnum.ALL.getAcctType());
                        payOrderInfo.setUserId(aliFundFreezeResponse.getPayerUserId());
                        payOrderInfo.setChannelOrderId(aliFundFreezeResponse.getAuthNo());
                        payOrderInfo.setChannelSeqNum(aliFundFreezeResponse.getOperationId());
                        JSONObject payerRemark = new JSONObject();
                        payerRemark.put("payerLogonId", aliFundFreezeResponse.getPayerLogonId());
                        String payerRemarkSt = JSON.toJSONString(payerRemark);
                        payOrderInfo.setPayerRemark(payerRemarkSt);
                        JSONObject payeeRemark;
                        if (!StringUtil.isEmptyOrNull(payOrderInfo.getPayeeRemark())) {
                            payeeRemark = JSONObject.parseObject(payOrderInfo.getPayeeRemark());
                        }else {
                            payeeRemark = new JSONObject();
                        }
                        payeeRemark.put("authNo", aliFundFreezeResponse.getAuthNo());
                        payeeRemark.put("operationId", aliFundFreezeResponse.getOperationId());
                        payeeRemark.put("gmtTrans", aliFundFreezeResponse.getGmtTrans());
                        payeeRemark.put("preAuthType", aliFundFreezeResponse.getPreAuthType());
                        payOrderInfo.setPayeeRemark(JSON.toJSONString(payeeRemark));
                        payOrderInfo.setPayeeRemark(JSON.toJSONString(payeeRemark));
                        payOrderInfo.setRespCode(aliFundFreezeResponse.getRespCode());
                        payOrderInfo.setRespDesc(aliFundFreezeResponse.getRespDesc());
                        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                        payOrderInfo.setBizStatus(BizStatusEnum.AUTH_INCOMPLETE.getStatus());
                        payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                    } else if ("INIT".equals(aliFundFreezeResponse.getStatus())) {
                        /* 预授权交易已创建，等待用户密码确认 */
                        mchntOrderInfoList.forEach(item -> item.setBizStatus(BizStatusEnum.PROCESSING.getStatus()));
                        userOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
                        payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
                        rglog.info("支付宝预授权状态<{}>", aliFundFreezeResponse.getStatus());
                    } else if ("CLOESD".equals(aliFundFreezeResponse.getStatus())) {
                        /* 更新当前用户订单信息 */
                        userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
                        userOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                        userOrderInfo.setBizStatus(BizStatusEnum.AUTH_INCOMPLETE.getStatus());
                        /* 更新当前商户订单信息 */
                        for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
                            mchntOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                            mchntOrderInfo.setBizStatus(BizStatusEnum.AUTH_INCOMPLETE.getStatus());
                            mchntOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        }
                        /* 更新当前支付订单信息 */
                        payOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                        payOrderInfo.setBizStatus(BizStatusEnum.AUTH_INCOMPLETE.getStatus());
                    } else {
                        rglog.info("支付宝预授权状态异常<{}>", aliFundFreezeResponse.getStatus());
                    }
                    break;
                case TRANS_TIMEOUT:
                    payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
                    break;
                case SYSTEM_REJECT:
                    if ("10003".equals(aliFundFreezeResponse.getRespCode()) || "20000".equals(aliFundFreezeResponse.getRespCode())) {
                        /*用户支付中，不做任何处理，在发起的异步查证中处理,用户订单和商户订单不做修改更新 */
                        payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
                        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
                    } else {
                        /* 更新当前用户订单信息 */
                        userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
                        userOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                        userOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                        userOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        /* 更新当前商户订单信息 */
                        for (MchntOrderInfo mchntOrderInfo : mchntOrderInfoList) {
                            mchntOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                            mchntOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                            mchntOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        }
                        /* 更新当前支付订单信息 */
                        payOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                        payOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                        payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
                        updateOrderInfo.setUserOrderInfo(userOrderInfo);
                        updateOrderInfo.setMchntOrderInfoList(mchntOrderInfoList);
                    }
                    break;
                default:
                    break;
            }
            updateOrderInfo.setPayOrderInfoList(Collections.singletonList(payOrderInfo));
        }
        return updateOrderInfo;
    }
}
